Relaxed Structure Assignment

The IDL “=” operator is unable to assign a structure value to a structure with a different definition. For example, suppose we have an existing structure definition SRC, as follows:

source = { SRC, A:FINDGEN(4), B:12 }

and we wish to create a second instance of the same structure, but with slightly different data and a different field:

dest = { SRC, A:INDGEN(2), C:20 }

Attempting to execute these two statements at the IDL command prompt gives the following results:

% Conflicting data structures: <INT Array[2]>,SRC.

% Execution halted at: $MAIN$

Versions of IDL beginning with IDL 5.1 include a mechanism to solve this problem. The STRUCT_ASSIGN procedure performs “relaxed structure assignment,” which is a field-by-field copy of a structure to another structure. Fields are copied according to the following rules:

  1. Any fields found in the destination structure that are not found in the source structure are “zeroed” (set to zero, the empty string, or a null pointer or object reference depending on the type of field).
  2. Any fields in the source structure that are not found in the destination structure are quietly ignored.
  3. Any fields that are found in both the source and destination structures are copied one at a time. If necessary, type conversion is done to make their types agree. If a field in the source structure has fewer data elements than the corresponding field in the destination structure, then the “extra” elements in the field in the destination structure are zeroed. If a field in the source structure has more elements than the corresponding field in the destination structure, the extra elements are quietly ignored.

Using STRUCT_ASSIGN, we can make the assignment that failed using the = operator:

source = { src, a:FINDGEN(4), b:12 }

dest = { dest, a:INDGEN(2), c:20 }

STRUCT_ASSIGN, source, dest, /VERBOSE

IDL prints:

% STRUCT_ASSIGN: SRC tag A is longer than destination.

                 The end will be clipped.

% STRUCT_ASSIGN: Destination lacks SRC tag B. Not copied.

If we check the variable dest, we see that it has the definition of the dest structure and the data from the source structure:

HELP, dest, /STRUCTURE

IDL prints:

** Structure DEST, 2 tags, length=6:

A INT Array[2]

C INT 0

Using Relaxed Structure Assignment

Why would you want to use Relaxed Structure Assignment? One case where this type of structure definition is very useful is in restoring object structures into an environment where the structure definition may have changed since the restored objects were saved.

Suppose you have created an application that saves data in structures. Your application may use the IDL SAVE routine to save the data structures to disk files. If you later change your application such that the definition of the data structures changes, you would not be able to restore your saved data into your application’s framework without relaxed structure assignment. The RELAXED_STRUCTURE_ASSIGNMENT keyword to the RESTORE procedure allows you to make relaxed assignments in such cases.

To see how this works, try the following exercise:

  1. Start IDL, create a named structure, and use the SAVE procedure to save it to a file:

    mystruct = { STR, A:10, B:20L, C:'a string' }

    SAVE, mystruct, FILE='test.dat'

  2. Exit and restart IDL.
  3. Create a new structure definition with the same name you used previously:

    newstruct = { STR, A:20L, B:10.0, C:'a string', D:ptr_new() }

  4. Attempt to restore the variable mystruct from the test.dat file:

    RESTORE, 'test.dat'

    IDL prints:

    % Wrong number of tags defined for structure: STR.

    % RESTORE: Structure not restored due to conflict with

               existing definition: STR.

  5. Now use relaxed structure definition when restoring:

    RESTORE, 'test.dat', /RELAXED_STRUCTURE_ASSIGNMENT

  6. Check the contents of mystruct:

    HELP, mystruct, /STRUCTURE

    IDL prints:

    ** Structure STR, 4 tags, length=20:

    A LONG 10

    B FLOAT 20.0000

    C STRING 'a string'

    D POINTER <NullPointer>

The structure in the variable mystruct now uses the definition from the new version of the STR structure, but contains the data from the old (restored) structure. In cases where the data type of a field has changed, the data type of the old data element has been converted to the new data type. Fields in the new structure definition that do not correspond to fields in the old definition contain “zero” values (zeroes for numeric fields, empty strings for string fields, null pointer or references for pointer or reference fields).